#include "lisctl.h"
#include "mysocket.h"
#include <netinet/tcp.h>
#include <errno.h>
#include "myposix.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "sys/socket.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

static int server_fd = -1;

int tcp_init(void)
{
    server_fd = socket_init();
    printf("%s|%s|%d:server_fd = %d\n", __FILE__, __func__, __LINE__, server_fd);
    return server_fd;
}

void tcp_final(void)
{
    if (-1 != server_fd)
    {
        close(server_fd);
        server_fd = -1;
    }
}

void *tcp_get(void *arg)
{
    if (-1 == server_fd)
    {
        server_fd = tcp_init();
        if (-1 == server_fd)
        {
            perror("tcp_init error");
            pthread_exit(0);
        }
    }

    mqd_t mqd = -1;
    posix_pt p = (posix_pt)arg;
    if (NULL != p)
    {
        mqd = p->mqd;
    }
    if (-1 == mqd)
    {
        printf("%s|%s|%d:mqd = %d\n", __FILE__, __func__, __LINE__, mqd);
        pthread_exit(0);
    }

    int cli_fd;
    int cli_len;
    int nread;
    unsigned char buf[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    struct sockaddr_in client;
    memset(&client, 0, sizeof(struct sockaddr_in));
    cli_len = sizeof(struct sockaddr_in);
    int keep_alive = 1;
    int keep_idle = 5;
    int keep_interval = 3;
    int keep_count = 3;

    pthread_detach(pthread_self());
    printf("%s thread start\n", __func__);
    while (1)
    {
        cli_fd = accept(server_fd, (struct sockaddr *)&client, &cli_len);
        if (cli_fd == -1)
        {
            perror("accept");
            continue;
        }

        if (-1 == setsockopt(cli_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keep_alive, sizeof(keep_alive)))
        {
            perror("SO_KEEPALIVE error");
            break;
        }
        if (-1 == setsockopt(cli_fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keep_idle, sizeof(keep_idle)))
        {
            perror("TCP_KEEPIDLE error");
            break;
        }
        if (-1 == setsockopt(cli_fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keep_interval, sizeof(keep_interval)))
        {
            perror("TCP_KEEPINTVL error");
            break;
        }
        if (-1 == setsockopt(cli_fd, IPPROTO_TCP, TCP_KEEPCNT, (void *)&keep_count, sizeof(keep_count)))
        {
            perror("TCP_KEEPCNT error");
            break;
        }

        printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
       
        while (1)
        {
            memset(buf, 0, sizeof(buf));
            nread = recv(cli_fd, buf, sizeof(buf), 0);
            printf("%s|%s|%d:nread = %d\n", __FILE__, __func__, __LINE__, nread);
            if (nread > 0)
            {
                if (buf[0] == 0xAA && buf[1] == 0x55 && buf[4] == 0x55 && buf[5] == 0xAA)
                {
                    printf("%s|%s|%d:gets->0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", __FILE__, __func__, __LINE__,
                           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
                    posix_send(mqd, buf, nread);
                }
            }
            else if (0 == nread || -1 == nread)
            {
                break;
            }
        }
        close(cli_fd);
    }
    pthread_exit(0);
}

listen_node socket_stu = {
    .listen_name = "socket",
    .init = tcp_init,
    .final = tcp_final,
    .get = tcp_get,
    .set = NULL,
    .next = NULL};

listen_pt tcp_add(listen_pt lisHead)
{
    return lis_add(lisHead, &socket_stu);
}